# parse graphviz commandline options as a single string
# This can be used to write your own dot program
# This can be used to create a fake dot program and redirect to another program of own choice
# Usage: dot [-Vv?] [-(GNE)name=val] [-(KTlso)<val>] <dot files>
# (additional options for neato)    [-x] [-n<v>]
# (additional options for fdp)      [-L(gO)] [-L(nUCT)<val>]
# (additional options for memtest)  [-m<v>]
# (additional options for config)  [-cv]
#
#  -V          - Print version and exit
#  -v          - Enable verbose mode 
#  -Gname=val  - Set graph attribute 'name' to 'val'
#  -Nname=val  - Set node attribute 'name' to 'val'
#  -Ename=val  - Set edge attribute 'name' to 'val'
#  -Tv         - Set output format to 'v'
#  -Kv         - Set layout engine to 'v' (overrides default based on command name)
#  -lv         - Use external library 'v'
#  -ofile      - Write output to 'file'
#  -O          - Automatically generate an output filename based on the input filename with a .'format' appended. (Causes all -ofile options to be ignored.) 
#  -P          - Internally generate a graph of the current plugins. 
#  -q[l]       - Set level of message suppression (=1)
#  -s[v]       - Scale input by 'v' (=72)
#  -y          - Invert y coordinate in output
#
#  -n[v]       - No layout mode 'v' (=1)
#  -x          - Reduce graph
#
#  -Lg         - Don't use grid
#  -LO         - Use old attractive force
#  -Ln<i>      - Set number of iterations to i
#  -LU<i>      - Set unscaled factor to i
#  -LC<v>      - Set overlap expansion factor to v
#  -LT[*]<v>   - Set temperature (temperature factor) to v
#
#  -m          - Memory test (Observe no growth with top. Kill when done.)
#  -m[v]       - Memory test - v iterations.
#
#  -c          - Configure plugins (Writes $prefix/lib/graphviz/config 
#                with available plugin information.  Needs write privilege.)
#  -?          - Print usage and exit

%prefix "gvoptions"

%source{

#include <stdio.h>

static const char *dbg_str[] = { "Evaluating rule", "Matched rule", "Abandoning rule" };

#define PCC_DEBUG(event, rule, level, pos, buffer, length) \
    fprintf(stdout, "%*s%s %s @%d [%.*s]\n", (int)(level * 2), "", dbg_str[event], rule, (int)pos, (int)length,  buffer); fflush(stdout)

    /* NOTE: To guarantee the output order, stderr, which can lead a race condition with stdout, is not used. */

}

optionsline	<- ('-' options)* !.

options	<- '?' _ { printf("option: -%s\n",$0); }
	/ 'c' _ { printf("option: -%s\n",$0); }
	/ 'x' _ { printf("option: -%s\n",$0); }
	/ 'v' _ { printf("option: -%s\n",$0); }
	/ 'V' _ { printf("option: -%s\n",$0); }
	/ 'O' _ { printf("option: -%s\n",$0); }
	/ 'P' _ { printf("option: -%s\n",$0); }
	/ 'y' _ { printf("option: -%s\n",$0); }
	/ 'LgO' _ { printf("option: -%s\n",$0); }
	/ 'Lg' _ { printf("option: -%s\n",$0); }
	/ 'LO' _ { printf("option: -%s\n",$0); }
	/ 'q' opt_q* _ { printf("option: -%s\n",$0); }
	/ 's' opt_s* _ { printf("option: -%s\n",$0); }
	/ 'n' opt_n* _ { printf("option: -%s\n",$0); }
	/ 'm' opt_m* _ { printf("option: -%s\n",$0); }
	/ 'Ln' opt_Ln _ { printf("option: -%s\n",$0); }
	/ 'LU' opt_LU _ { printf("option: -%s\n",$0); }
	/ 'LC' opt_LC _ { printf("option: -%s\n",$0); }
	/ 'LT' opt_LT _ { printf("option: -%s\n",$0); }
	/ 'o' opt_o _ { printf("option: -%s\n",$0); }
	/ 'G'(!sp .) opt_G _ { printf("option: -%s\n",$0); }
	/ 'N'(!sp .) opt_N _ { printf("option: -%s\n",$0); }
	/ 'E'(!sp .) opt_E _ { printf("option: -%s\n",$0); }
	/ 'T' opt_T _ { printf("option: -%s\n",$0); }
	/ 'l' opt_l _ { printf("option: -%s\n",$0); }
	/ 'K' opt_K _ { printf("option: -%s\n",$0); }

opt_q	<-	[1-9]+('.'[0-9]*)?
		/ [0-9][1-9]+('.'[0-9]*)?
		/ [0]+('.'[0-9]*)? { printf("illegal value for option: -q%s\n",$0); }

opt_s	<-	digit+('.'digit*)?

opt_n	<-	[1-9]+('.'[0-9]*)?
		/ [0-9][1-9]+('.'[0-9]*)?
		/ [0]+('.'[0-9]*)? { printf("illegal value for option: -n%s\n",$0); }

opt_m	<-	[1-9]+('.'[0-9]*)?
		/ [0-9][1-9]+('.'[0-9]*)?
		/ [0]+('.'[0-9]*)? { printf("illegal value for option: -m%s\n",$0); }

opt_Ln	<-	digit+('.'[0-9]*)?

opt_LU	<-	digit+('.'[0-9]*)?

opt_LC	<-	digit*('.'[0-9]*)?

opt_LT	<-	'*'*digit*('.'[0-9]*)?

opt_o	<-	.(!'-' .)*

opt_l	<-	.(!'-' .)*

opt_G	<-	(!'-' .)*

opt_N	<-	(!'-' .)*

opt_E	<-	(!'-' .)*

opt_K	<-	 (!'-' ' ')* opt_Klayouts

opt_Klayouts	<- 'circo'
		/ 'dot'
		/ 'fdp'
		/ 'neato'
		/ 'nop'
		/ 'nop1'
		/ 'nop2'
		/ 'osage'
		/ 'patchwork'
		/ 'sfdp'
		/ 'twopi'


opt_T	<-	opt_Tformat (':' (!sp .) opt_Trenderer (':' opt_Tformatter)? )?

opt_Trenderer	<- (!':' !'-' .)*

opt_Tformatter	<- (!'-' .)*

opt_Tformat	<- 'bmp'
		/ 'canon'
		/ 'cmap'
		/ 'cmapx'
		/ 'cmapx_np'
		/ 'dot'
		/ 'dot_json'
		/ 'eps'
		/ 'fig'
		/ 'gd'
		/ 'gd2'
		/ 'gif'
		/ 'gtk'
		/ 'gv'
		/ 'ico'
		/ 'imap'
		/ 'imap'
		/ 'np'
		/ 'ismap'
		/ 'jpe'
		/ 'jpeg'
		/ 'jpg'
		/ 'json'
		/ 'json0'
		/ 'mp'
		/ 'pdf'
		/ 'pic'
		/ 'plain'
		/ 'plain-ext'
		/ 'png'
		/ 'pov'
		/ 'ps ps2'
		/ 'svg'
		/ 'svgz'
		/ 'tif'
		/ 'tiff'
		/ 'tk'
		/ 'vml'
		/ 'vmlz'
		/ 'vrml'
		/ 'wbmp'
		/ 'x11'
		/ 'xdot'
		/ 'xdot1.2'
		/ 'xdot1.4'
		/ 'xdot_json'
		/ 'xlib'
		/ '?.'


digit	<-	[0-9]+

sp	<-	[ \t\n\r]

_	<-	[ \t\n\r]*

%%

int main() {
    gvoptions_context_t *ctx=gvoptions_create(NULL);
    while (gvoptions_parse(ctx, NULL)){;}
    gvoptions_destroy(ctx);
    return 0;
}
